﻿using Xejen.Ipc.Framework.Controllers;
using Xejen.Ipc.Framework.Flows;
using Xejen.Ipc.Framework.Steps;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace Xejen.Ipc.Framework.Controllers
{
    /// <inheritdoc cref="IControllerBuilder{TData}"/>
    internal class ControllerBuilder<TData> : IControllerBuilder<TData>
        where TData : new()
    {
        private readonly ILogger _logger;
        private readonly List<IController<TData>> _controllers = new List<IController<TData>>();

        private readonly StepProvider<TData> _provider = new StepProvider<TData>();

        /// <inheritdoc cref="ControllerBuilder{TData}"/>
        public ControllerBuilder()
        {
            _logger = HostRuntime.LoggerManager.CreateLogger<ControllerBuilder<TData>>();
        }

        /// <inheritdoc/>
        public IControllerBuilder<TData> Then(params Func<IStepProvider<TData>, IStep<TData>>[] stepBuilders)
        {
            List<IStep<TData>> steps = CreateSteps(stepBuilders);
            _controllers.Add(new Then<TData>(steps.ToArray()));

            LogInformation($"添加 {nameof(Then)} 流程控制器，包含如下步骤：{string.Join(",", steps.Select(q => q.Name).ToArray())}");

            return this;
        }

        /// <inheritdoc/>
        public IControllerBuilder<TData> Any(params Func<IStepProvider<TData>, IStep<TData>>[] stepBuilders)
        {
            List<IStep<TData>> steps = CreateSteps(stepBuilders);
            _controllers.Add(new Any<TData>(steps.ToArray()));

            LogInformation($"添加 {nameof(Any)} 流程控制器，包含如下步骤：{string.Join(",", steps.Select(q => q.Name).ToArray())}");

            return this;
        }

        /// <inheritdoc/>
        public IControllerBuilder<TData> All(params Func<IStepProvider<TData>, IStep<TData>>[] stepBuilders)
        {
            List<IStep<TData>> steps = CreateSteps(stepBuilders);
            _controllers.Add(new All<TData>(steps.ToArray()));

            LogInformation($"添加 {nameof(All)} 流程控制器，包含如下步骤：{string.Join(",", steps.Select(q => q.Name).ToArray())}");

            return this;
        }

        /// <inheritdoc/>
        public IControllerBuilder<TData> If(Func<TData, bool> condition, Action<TData> @else = null, params Func<IStepProvider<TData>, IStep<TData>>[] stepBuilders)
        {
            List<IStep<TData>> steps = CreateSteps(stepBuilders);
            _controllers.Add(new If<TData>(condition, @else, steps.ToArray()));

            LogInformation($"添加 {nameof(If)} 流程控制器，包含如下步骤：{string.Join(",", steps.Select(q => q.Name).ToArray())}");

            return this;
        }

        /// <summary>
        /// 通过步骤构建器生成步骤列表
        /// </summary>
        /// <param name="stepBuilders">步骤构建器的集合</param>
        /// <returns></returns>
        private List<IStep<TData>> CreateSteps(Func<IStepProvider<TData>, IStep<TData>>[] stepBuilders)
        {
            List<IStep<TData>> steps = new List<IStep<TData>>();
            stepBuilders.ForEach((stepBuilder) =>
            {
                steps.Add(stepBuilder(_provider));
            });

            return steps;
        }

        /// <inheritdoc/>
        public IFlow<TData> Build(string flowName, IFlow<TData> parent)
        {
            Flow<TData> flow;
            if (parent == null)
            {
                flow = new Flow<TData>(flowName);
            }
            else
            {
                flow = new Flow<TData>(flowName, parent);
            }

            for (var i = 0; i <= _controllers.Count - 1; i++)
            {
                Controller<TData> controller = _controllers[i] as Controller<TData>;
                if (i != _controllers.Count - 1)
                {
                    controller.SetNext(_controllers[i + 1]);
                }
            }

            flow.Controllers = _controllers.AsReadOnly();

            return flow;
        }

        private void LogInformation(string content)
        {
            Debug.WriteLine(content);
            _logger.LogInformation(content);
        }
    }
}
